package com.joinway.framework.support.facade;

import org.apache.commons.lang3.StringUtils;
import org.aspectj.lang.ProceedingJoinPoint;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.bind.MethodArgumentNotValidException;

import com.joinway.framework.bean.exception.ValidationException;
import com.joinway.framework.bean.view.View;
import com.joinway.framework.core.utils.AopHelper;
import com.joinway.framework.support.logging.service.impl.EventLogService;

public class FacadeAspect {

	private final static Logger log = LoggerFactory.getLogger(FacadeAspect.class);
	
	private String validationFailCode;
	
	private String validationFailMessage;
	
	private String errorCode;
	
	private String errorMessage;
	
	private EventLogService eventLogService;
	
	public Object doAround(ProceedingJoinPoint point) {
		Object value = null;
		
		Class<?> returnType = AopHelper.getMethod(point).getReturnType();
		
		try{
			value = point.proceed(point.getArgs());
		}catch(MethodArgumentNotValidException | javax.validation.ValidationException e){
			printExceptionTrace("validate input arguments failed", e);
			value = createInstance(returnType);
			if(value instanceof View){
				View view = (View)value;
				view.setCode(getValidationFailCode());
				view.setMessage(getValidationFailMessage());
			}
		}catch(ValidationException ve){
			printExceptionTrace("biz validation failed", ve);
			value = createInstance(returnType);
			if(value instanceof View){
				View view = (View)value;
				view.setCode(ve.getCode());
				view.setMessage(ve.getMessage());
			}
		}catch(Throwable t){
			printExceptionTrace("failed to process incomming request ", t);
			value = createInstance(returnType);
			if(value instanceof View){
				View view = (View)value;
				if(StringUtils.isBlank(errorCode)){
					view.setCode(getErrorCode());
				}
				if(StringUtils.isBlank(errorMessage)){
					view.setMessage(getErrorMessage());
				}
			}
		}
		
		return value;
	}
	
	protected<T> T createInstance(Class<T> type){
		T value = null;
		
		try{
			value = type.newInstance();
		}catch(Exception e){
			log.error("failed to create instance of class " + type.getCanonicalName(), e);
		}
		
		return value;
	}

	protected void raiseErrorEvent(Throwable t){
		// do nothing
	}
	
	protected void printExceptionTrace(String message, Throwable t){
		log.error(message, t);
	}
	
	public String getValidationFailCode() {
		return validationFailCode;
	}

	public void setValidationFailCode(String validationFailCode) {
		this.validationFailCode = validationFailCode;
	}

	public String getValidationFailMessage() {
		return validationFailMessage;
	}

	public void setValidationFailMessage(String validationFailMessage) {
		this.validationFailMessage = validationFailMessage;
	}

	public String getErrorCode() {
		return errorCode;
	}

	public void setErrorCode(String errorCode) {
		this.errorCode = errorCode;
	}

	public String getErrorMessage() {
		return errorMessage;
	}

	public void setErrorMessage(String errorMessage) {
		this.errorMessage = errorMessage;
	}

	public EventLogService getEventLogService() {
		return eventLogService;
	}

	public void setEventLogService(EventLogService eventLogService) {
		this.eventLogService = eventLogService;
	}
}

